package com.zpark.transaction.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zpark.jushanpay.common.domain.BusinessException;
import com.zpark.jushanpay.common.domain.CommonErrorCode;
import com.zpark.jushanpay.common.util.RedisUtil;
import com.zpark.jushanpay.common.util.StringUtil;
import com.zpark.transaction.api.dto.PayChannelDTO;
import com.zpark.transaction.api.dto.PayChannelParamDTO;
import com.zpark.transaction.api.dto.PlatformChannelDTO;
import com.zpark.transaction.api.service.IPayChannelService;
import com.zpark.transaction.service.convert.IPayChannelConvert;
import com.zpark.transaction.service.convert.IPayChannelParamConvert;
import com.zpark.transaction.service.convert.IPlatFormChannelConvert;
import com.zpark.transaction.service.entity.AppPlatformChannel;
import com.zpark.transaction.service.entity.PayChannel;
import com.zpark.transaction.service.entity.PayChannelParam;
import com.zpark.transaction.service.entity.PlatformChannel;
import com.zpark.transaction.service.mapper.IAppPlatformChannelMapper;
import com.zpark.transaction.service.mapper.IPayChannelParamMapper;
import com.zpark.transaction.service.mapper.IPlatformChannelMapper;
import com.zpark.transaction.service.util.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 业务层接口实现类
 */
@Service
public class PayChannelServiceImpl implements IPayChannelService {

    @Autowired
    private IPlatformChannelMapper platformChannelMapper;

    @Autowired
    private IAppPlatformChannelMapper appPlatformChannelMapper;

    @Autowired
    private IPayChannelParamMapper payChannelParamMapper;

    @Autowired
    private RedisCache cache;

    /**
     * 查询所有平台服务类型数据
     * @return
     * @throws BusinessException
     */
    @Override
    public List<PlatformChannelDTO> queryPlatformChannelAll() throws BusinessException {
        // 1、调用持久层方法查询数据  selectList
        List<PlatformChannel> platformChannels = platformChannelMapper.selectList(null);
        // 2、判断查询结果是否有数据，没有数据则抛出异常
        if (platformChannels == null || platformChannels.size() <= 0) {
            throw new BusinessException(CommonErrorCode.E_200207);
        }
        // 3、将entity转为dto返回
        return IPlatFormChannelConvert.INSTANCE.listEntityToListDto(platformChannels);
    }

    /**
     * 应用绑定平台服务类型
     * @param appId 应用的appId
     * @param platformChannelCode 平台服务类型编码
     * @throws BusinessException
     */
    @Override
    public void bindPlatformChannelForApp(String appId, String platformChannelCode) throws BusinessException {
        // 判断参数是否为空
        if (StringUtil.isEmpty(appId) || StringUtil.isEmpty(platformChannelCode)) {
            throw new BusinessException(CommonErrorCode.E_200202);
        }

        // 根据platformChannelCode查询数据（platform_channel表）
        PlatformChannel platformChannel = platformChannelMapper.selectOne(
                new LambdaQueryWrapper<PlatformChannel>()
                        .eq(PlatformChannel::getChannelCode, platformChannelCode)
        );
        if (platformChannel == null) {
            throw new BusinessException(CommonErrorCode.E_200005);
        }
        // 根据appId和platformChannelCode查询数据（app_platform_channel表）
        AppPlatformChannel appPlatformChannel = queryAppPlatByAppIdPlatChannel(appId, platformChannelCode);
        // 判断查询结果是否为空，如果为空则没有绑定服务，否则不用绑定
        if (appPlatformChannel == null) {
            // 结果为空，则将数据保存到数据库（app_platform_channel表）
            appPlatformChannel = new AppPlatformChannel();

            appPlatformChannel.setAppId(appId);
            appPlatformChannel.setPlatformChannel(platformChannelCode);

            appPlatformChannelMapper.insert(appPlatformChannel);
        }
    }

    /**
     * 查询应用与平台支付渠道类型是否绑定
     * @param appId 应用appId
     * @param platformChannelCode 应用平台支付渠道类型编码
     * @return
     * @throws BusinessException
     */
    @Override
    public Integer queryAppBindPlatformChannel(String appId, String platformChannelCode) throws BusinessException {
        // 根据appId和code查询数据
        Long count = queryAppPlatformByAppIdPlatformChannelCode(appId, platformChannelCode);
        // 将结果返回
        if (count > 0) {
            // 绑定
            return 1;
        } else {
            // 未绑定
            return 0;
        }
    }

    /**
     * 根据平台服务类型编码查询原始支付渠道数据
     * @param platformChannelCode 平台服务类型编码
     * @return
     * @throws BusinessException
     */
    @Override
    public List<PayChannelDTO> queryPayChannelByPlatformChannel(String platformChannelCode) throws BusinessException {
        // 调用持久层接口查询数据
        List<PayChannel> payChannels =
                platformChannelMapper.selectPayChannelByPlatformChannel(platformChannelCode);
        // 将entity转为dto返回
        return IPayChannelConvert.INSTANCE.listEntityToListDto(payChannels);
    }

    /**
     * 保存支付渠道参数配置
     * @param dto 支付渠道参数对象
     * @throws BusinessException
     */
    @Override
    public void savePayChannelParam(PayChannelParamDTO dto) throws BusinessException {
        // 判断参数是否齐全（appId、platformChannelCode、payChannel）
        if (dto == null || StringUtil.isEmpty(dto.getAppId())
            || StringUtil.isEmpty(dto.getPlatformChannelCode())
            || StringUtil.isEmpty(dto.getPayChannel())) {
            throw new BusinessException(CommonErrorCode.E_200006);
        }
        // 根据appId查询应用与平台服务类型是否绑定
        AppPlatformChannel appParam =
                queryAppPlatByAppIdPlatChannel(dto.getAppId(), dto.getPlatformChannelCode());
        if (appParam == null) {
            throw new BusinessException(CommonErrorCode.E_200210);
        }

        // 根据应用与服务类型绑定id和支付渠道查询参数信息
        PayChannelParam payChannelParam = payChannelParamMapper.selectOne(
                new LambdaQueryWrapper<PayChannelParam>()
                        .eq(PayChannelParam::getAppPlatformChannelId, appParam.getId())
                        .eq(PayChannelParam::getPayChannel, dto.getPayChannel())
        );
        // 将dto转为entity
        PayChannelParam param = IPayChannelParamConvert.INSTANCE.dtoToEntity(dto);
        // 设置应用与平台服务绑定的ID
        param.setAppPlatformChannelId(appParam.getId());
        // 查询有结果，更新支付渠道参数
        if (payChannelParam != null) {
            // 设置Id
            param.setId(payChannelParam.getId());

            // 调用持久层方法更新数据
            payChannelParamMapper.updateById(param);
        } else {
            // 没有结果，新增支付渠道参数配置
            payChannelParamMapper.insert(param);
        }

        // 将支付参数缓存到redis
        updateCache(appParam.getAppId(), appParam.getPlatformChannel());
    }

    /**
     * 根据应用的appId和平台服务类型编码查询原始支付渠道参数配置数据
     * @param appId 应用的appId
     * @param platformChannelCode 平台服务类型编码
     * @return
     * @throws BusinessException
     */
    @Override
    public List<PayChannelParamDTO> queryPayChannelParamByAppAndPlatform(
            String appId, String platformChannelCode) throws BusinessException {
        /***************************** 从redis缓存获取数据开始 **************************************/
        // 确认key
        String key = RedisUtil.keyBuilder(appId, platformChannelCode);
        // 根据key查询数据
        String resultParam = cache.get(key);
        // 判断查询结果
        if (!StringUtil.isEmpty(resultParam)) {
            // 将json字符串转为Java对象
            List<PayChannelParamDTO> paramDTOS =
                    JSON.parseArray(resultParam, PayChannelParamDTO.class);
            // 返回支付参数结果对象
            return paramDTOS;
        }

        /***************************** 从redis缓存获取数据结束 **************************************/

        // 根据appID和code查询表app_platform_channel
        AppPlatformChannel appPlatformChannel =
                queryAppPlatByAppIdPlatChannel(appId, platformChannelCode);
        // 判断是否有结果，没有结果则抛出异常
        if (appPlatformChannel == null) {
            throw new BusinessException(CommonErrorCode.E_200210);
        }
        // 根据应用与平台服务类型的ID查询支付参数
        List<PayChannelParam> payChannelParams = payChannelParamMapper.selectList(
                new LambdaQueryWrapper<PayChannelParam>()
                        .eq(PayChannelParam::getAppPlatformChannelId, appPlatformChannel.getId())
        );

        /***************************** 缓存数据到redis开始 **************************************/
        //存入缓存
        updateCache(appId, platformChannelCode);
        /***************************** 缓存数据到redis结束 **************************************/

        // 将结果返回
        return IPayChannelParamConvert.INSTANCE.listEntityToListDto(payChannelParams);
    }

    /**
     * 根据应用的appId和平台服务类型编码以及原始支付渠道编码查询原始支付渠道参数配置数据
     * @param appId 应用的appId
     * @param platformChannelCode 平台服务类型编码
     * @param payChannel 原始支付渠道编码
     * @return
     * @throws BusinessException
     */
    @Override
    public PayChannelParamDTO queryPayChannelParamByAppAndPlatform(String appId, String platformChannelCode, String payChannel) throws BusinessException {

        // 调用根据应用的appId和平台服务类型编码查询原始支付渠道参数配置数据方法
        List<PayChannelParamDTO> paramDTOS =
                queryPayChannelParamByAppAndPlatform(appId, platformChannelCode);

        // 判断查询结果是否满秩指定的通道，如果满足则返回结果
        for (PayChannelParamDTO paramDTO : paramDTOS) {
            // 判断查询结果对象当中的原始支付渠道是否与给定的一致
            if (paramDTO.getPayChannel().equals(payChannel)) {
                // 一致，则返回该对象
                return paramDTO;
            }
        }
        // 不一致，返回null
        return null;
    }


    /**
     * 内部方法：
     *  根据appid查询应用与指定的平台服务类型是否绑定
     * @param appId 应用appId
     * @param platformChannelCode 平台服务类型编码
     * @return
     */
    private Long queryAppPlatformByAppIdPlatformChannelCode(String appId, String platformChannelCode){
        return appPlatformChannelMapper.selectCount(
                new LambdaQueryWrapper<AppPlatformChannel>()
                        .eq(AppPlatformChannel::getAppId, appId)
                        .eq(AppPlatformChannel::getPlatformChannel, platformChannelCode)
        );
    }

    /**
     * 内部方法：
     *  根据appid查询应用与指定的平台服务类型数据
     * @param appId 应用appId
     * @param platformChannelCode 平台服务类型编码
     * @return
     */
    private AppPlatformChannel queryAppPlatByAppIdPlatChannel(String appId, String platformChannelCode){
        return appPlatformChannelMapper.selectOne(
                new LambdaQueryWrapper<AppPlatformChannel>()
                        .eq(AppPlatformChannel::getAppId, appId)
                        .eq(AppPlatformChannel::getPlatformChannel, platformChannelCode)
        );
    }


    /**
     * redis缓存支付渠道参数
     * @param appId 用于appId
     * @param platformChannel 支付渠道类型
     */
    private void updateCache(String appId, String platformChannel){
        // 生成key
        // 1、key的构建，如：SJ_PAY_PARAM:b910da455bc84514b324656e1088320b:shanju_c2b
        String key = RedisUtil.keyBuilder(appId, platformChannel);
        // 2、判断key是否存在，如果key存在则删除key
        if (cache.exists(key)) {
            // 删除key
            cache.del(key);
        }

        // 3、从数据库查询应用的服务类型对应的实际支付参数，并且重新存入redis缓存
        // 根据appID和code查询表app_platform_channel
        AppPlatformChannel appPlatformChannel =
                queryAppPlatByAppIdPlatChannel(appId, platformChannel);
        // 判断是否有结果，没有结果则抛出异常
        if (appPlatformChannel == null) {
            throw new BusinessException(CommonErrorCode.E_200210);
        }
        // 根据应用与平台服务类型的ID查询支付参数
        List<PayChannelParam> paramDTOS = payChannelParamMapper.selectList(
                new LambdaQueryWrapper<PayChannelParam>()
                        .eq(PayChannelParam::getAppPlatformChannelId, appPlatformChannel.getId())
        );

        // 判断支付参数对象是否为空
        if (paramDTOS != null) {
            // 缓存支付参数
            cache.set(key, JSON.toJSONString(paramDTOS));
        }

    }

}
